/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package ebookmgr;

import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowEvent;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.WindowAdapter;
import java.awt.dnd.DropTarget;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.sql.Connection;
import java.util.Vector;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeSelectionModel;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.FocusAdapter;
import java.awt.event.KeyAdapter;
import java.util.List;

/**
 * Created by mazhao@dl.cn. User: mazhao Date: 2009-9-5 Time: 22:03:46 Welcome
 * to Dalian.
 */
public class MainFrame extends JFrame {

    // left catalog tree
    final private JTree catalogTree = new JTree();
    // current selected catalog tree path
    // like "\Computer Books\Programming Language\Java"
    private String currentSelectedCatalogTreePath = null;
    // right table for book showing
    final private JTable bookTable = new JTable();
    // Popup Menu on Catalog Tree
    final private JPopupMenu catalogTreePopupMenu = new JPopupMenu();
    // HSQLDB Database Connection
    private Connection conn = null;

    public JTree getCatalogTree() {
        return this.catalogTree;
    }

    public MainFrame() {

        // ======================
        // Initialize main frame
        // ======================
        initFrame();

        // ======================
        // Main Area
        // ======================

        // main split pane
        JSplitPane splitPane = new JSplitPane();
        splitPane.setDividerLocation(200);
        splitPane.setAutoscrolls(true);
        splitPane.setOneTouchExpandable(true);


        // ==== Main Left ====
        JPanel leftPanel = new JPanel();
        leftPanel.setBorder(BorderFactory.createEtchedBorder());
        leftPanel.setLayout(new BorderLayout());

        // create folder tree, init, add to left panel

        initPopupMenu();
        initTree();

        JScrollPane fts = new JScrollPane(catalogTree);
        leftPanel.add(fts, BorderLayout.CENTER);

        JPanel leftCtrlPanel = createLeftCtrlPanel();
        leftPanel.add(leftCtrlPanel, BorderLayout.SOUTH);

        // ==== Main Right ====
        JPanel rightPanel = new JPanel();
        rightPanel.setLayout(new BorderLayout());

        initBookTable();
        JScrollPane rightScrollPane = new JScrollPane(bookTable);
        
        rightPanel.add(rightScrollPane, BorderLayout.CENTER);
        rightPanel.setBorder(BorderFactory.createEtchedBorder());


        splitPane.setLeftComponent(leftPanel);
        splitPane.setRightComponent(rightPanel);

        this.add(splitPane, BorderLayout.CENTER);

        // ======================
        // Toolbar Area
        // ======================
        JToolBar toolBar = createToolBar();
        this.add(toolBar, BorderLayout.NORTH);

        // ======================
        // Menu Area
        // ======================

        JMenuBar menuBar = createMenuBar();

        this.setJMenuBar(menuBar);

        // ======================
        // pack main frame.
        // ======================
        this.pack();



    }
    // ==============================================================
    // Initialization UI Section
    // ==============================================================
    
    private void initBookTable() {
        // each time select one and only one row
        bookTable.setRowSelectionAllowed(true);
        bookTable.setColumnSelectionAllowed(false);
        bookTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        bookTable.setModel(new BookTableModel());
        bookTable.setRowHeight(24);
        bookTable.setRowMargin(2);
        bookTable.setGridColor(Color.GRAY);
        bookTable.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() == 2) {
                    openBook();
                }
            }
        });
        DropTarget dtBookTable = new DropTarget(bookTable, new CopyFileDropListener());
    }

    private void initFrame() {

        // set title
        this.setTitle(Configuration.getUIString("MainFrame.Title"));

        // set icon image
        URL imageUrl = getClass().getResource("images/ebookmgr.jpg");
        ImageIcon frameicon = new ImageIcon(imageUrl);
        this.setIconImage(frameicon.getImage());

        // set frame location
        this.setLocation(0, 0);

        Dimension mainWindowDimension = new Dimension(1024, 768);
        // set frame size
        this.setPreferredSize(mainWindowDimension);

        // set frame layout
        this.setLayout(new BorderLayout());


        // add windows listener
        // for performance reason:
        // 1. open connection when main frame is opened.
        // 2. close connection until main frame is closed.
        this.addWindowListener(new WindowAdapter() {

            /**
             * close hsqldb database connection
             */
            private void closeConnectionAndExit() {
                DatabaseUtil.disconnect(conn);
                System.exit(0);
            }

            /**
             * for windows only.
             */
            @Override
            public void windowClosed(WindowEvent e) {
                closeConnectionAndExit();
            }

            /**
             * for mac and linux
             */
            @Override
            public void windowClosing(WindowEvent e) {
                closeConnectionAndExit();
            }

            @Override
            public void windowOpened(WindowEvent e) {
                conn = DatabaseUtil.connect();
            }
        });
    }

    private JPanel createLeftCtrlPanel() {
        // create left control panel(downside)
        JPanel leftCtrlPanel = new JPanel();
        leftCtrlPanel.setLayout(new FlowLayout());
        Dimension treeToolBtnDimension = new Dimension(50, 25);

        JButton plusButton = new JButton(Configuration.getUIString("MainFrame.Plus"));
        plusButton.setSize(treeToolBtnDimension);
        plusButton.setPreferredSize(treeToolBtnDimension);
        plusButton.setMaximumSize(treeToolBtnDimension);
        plusButton.setMinimumSize(treeToolBtnDimension);
        plusButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                treeAddClick();
            }
        });

        JButton minusButton = new JButton(Configuration.getUIString("MainFrame.Minus"));
        minusButton.setSize(treeToolBtnDimension);
        minusButton.setPreferredSize(treeToolBtnDimension);
        minusButton.setMaximumSize(treeToolBtnDimension);
        minusButton.setMinimumSize(treeToolBtnDimension);
        minusButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                treeDelClick();
            }
        });

        JButton configureButton = new JButton(Configuration.getUIString("MainFrame.Ellipsis"));
        configureButton.setSize(treeToolBtnDimension);
        configureButton.setPreferredSize(treeToolBtnDimension);
        configureButton.setMaximumSize(treeToolBtnDimension);
        configureButton.setMinimumSize(treeToolBtnDimension);
        configureButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                treeConfClick();
            }
        });

        leftCtrlPanel.add(plusButton);
        leftCtrlPanel.add(minusButton);
        leftCtrlPanel.add(configureButton);
        return leftCtrlPanel;
    }

    private JMenuBar createMenuBar() {
        JMenuBar menuBar = new JMenuBar();

        // File Menu Section
        JMenu fileMenu = new JMenu(Configuration.getUIString("MainFrame.Menu.File"));
        fileMenu.setMnemonic('f');
        JMenuItem importItem = new JMenuItem(Configuration.getUIString("MainFrame.Menu.Import"), new ImageIcon(getClass().getResource("images/menu/setting.png")));
        importItem.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                importClick();
            }
        });

        JMenuItem setItem = new JMenuItem(Configuration.getUIString("MainFrame.Menu.Setting"), new ImageIcon(getClass().getResource("images/menu/setting.png")));
        setItem.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                showSettingDialog();
            }
        });

        JMenuItem exitItem = new JMenuItem(Configuration.getUIString("MainFrame.Menu.Exit"), new ImageIcon(getClass().getResource("images/menu/exit.png")));
        exitItem.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                exitItemClick();
            }
        });

        fileMenu.add(importItem);
        fileMenu.addSeparator();
        fileMenu.add(setItem);
        fileMenu.addSeparator();
        fileMenu.add(exitItem);
        menuBar.add(fileMenu);

        // Edit Menu Section
        JMenu editMenu = new JMenu(Configuration.getUIString("MainFrame.Menu.Catalog"));
        editMenu.setMnemonic('e');
        JMenuItem addItem = new JMenuItem(Configuration.getUIString("MainFrame.Add"), new ImageIcon(getClass().getResource("images/menu/add.png")));
        addItem.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                treeAddClick();
            }
        });
        JMenuItem deleteItem = new JMenuItem(Configuration.getUIString("MainFrame.Delete"), new ImageIcon(getClass().getResource("images/menu/delete.png")));
        deleteItem.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                treeDelClick();
            }
        });
        JMenuItem confItem = new JMenuItem(Configuration.getUIString("MainFrame.Configure"), new ImageIcon(getClass().getResource("images/menu/config.png")));
        confItem.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                treeConfClick();
            }
        });
        editMenu.add(addItem);
        editMenu.add(deleteItem);
        editMenu.add(confItem);
        menuBar.add(editMenu);

        JMenu ebookMenu = new JMenu(Configuration.getUIString("MainFrame.Menu.EBook"));
        JMenuItem deleteEbookItem = new JMenuItem(Configuration.getUIString("MainFrame.Menu.DeleteEBook"));
        deleteEbookItem.addActionListener(new ActionListener(){

            @Override
            public void actionPerformed(ActionEvent e) {
                deleteBook();
            }
        });
        JMenuItem openEbookItem = new JMenuItem(Configuration.getUIString("MainFrame.Menu.OpenEBook"));
        openEbookItem.addActionListener(new ActionListener(){

            @Override
            public void actionPerformed(ActionEvent e) {
                openBook();
            }

        });
        JMenuItem renameEbookItem = new JMenuItem(Configuration.getUIString("MainFrame.Menu.RenameEBook"));
        renameEbookItem.addActionListener(new ActionListener(){

            @Override
            public void actionPerformed(ActionEvent e) {
                renameBook();
            }
            
        });

        ebookMenu.add((deleteEbookItem));
        ebookMenu.add(openEbookItem);
        ebookMenu.add(renameEbookItem);
        menuBar.add(ebookMenu);
        
        // Help Menu Section
        JMenu helpMenu = new JMenu(Configuration.getUIString("MainFrame.Menu.Help"));
        helpMenu.setMnemonic('h');
        JMenuItem helpItem = new JMenuItem(Configuration.getUIString("MainFrame.Menu.Content"), new ImageIcon(getClass().getResource("images/menu/help.png")));
        helpItem.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                showHelpContent();
            }
        });
        JMenuItem aboutItem = new JMenuItem(Configuration.getUIString("MainFrame.Menu.About"), new ImageIcon(getClass().getResource("images/menu/about.png")));
        aboutItem.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                showAboutDialog();
            }
        });

        helpMenu.add(helpItem);
        helpMenu.add(aboutItem);
        menuBar.add(helpMenu);
        return menuBar;
    }

    private JToolBar createToolBar() {
        JToolBar toolBar = new JToolBar();

        URL imgURL = getClass().getResource("images/toolbar/view-refresh.png");
        ImageIcon icon = new ImageIcon(imgURL);
        JButton importButton = new JButton(icon);
        importButton.setToolTipText(Configuration.getUIString("MainFrame.ToolTips.Import"));
        importButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                importClick();
            }
        });

        imgURL = getClass().getResource("images/toolbar/preferences-system.png");
        icon = new ImageIcon(imgURL);
        //JButton settingBtn = new JButton(Configuration.getUIString("MainFrame.Menu.Setting"), icon);
        JButton settingBtn = new JButton(icon);
        settingBtn.setToolTipText(Configuration.getUIString("MainFrame.ToolTips.Setting"));
        settingBtn.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                showSettingDialog();
            }
        });

        final JTextField searchText = new JTextField();
        searchText.setText(Configuration.getUIString("MainFrame.Search"));
        Dimension d = new Dimension(200, 24);
        searchText.setSize(d);
        searchText.setPreferredSize(d);
        searchText.setMaximumSize(d);
        searchText.setMinimumSize(d);
        searchText.addFocusListener(new FocusAdapter(){

            @Override
            public void focusGained(FocusEvent e) {
                    if(Configuration.getUIString("MainFrame.Search").equalsIgnoreCase(searchText.getText())) {
                        searchText.setText("");
                    }
            }

            @Override
            public void focusLost(FocusEvent e) {
                if(searchText.getText() == null || searchText.getText().length() == 0) {
                    searchText.setText(Configuration.getUIString("MainFrame.Search"));
                }
            }
        });

        searchText.addKeyListener(new KeyAdapter(){

            @Override
            public void keyTyped(KeyEvent e) {
                searchForBook(e);
            }

            @Override
            public void keyPressed(KeyEvent e) {
                
            }

            @Override
            public void keyReleased(KeyEvent e) {
                searchForBook(e);
            }

            private void searchForBook(KeyEvent e) {
                if (e.getKeyCode() == 10) {
                    String searchKey = searchText.getText();
                    searchBook(searchKey);
                }
            }

        });


        toolBar.add(importButton);
        toolBar.addSeparator();
        toolBar.add(settingBtn);
        // add component at right side of menu or toolbar.
        toolBar.add(Box.createHorizontalGlue());
        toolBar.add(searchText);
        
        return toolBar;
    }

    private void initTree() {

        catalogTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

        TreeModel tm = TreeUtil.loadTree();
        catalogTree.setModel(tm);

        catalogTree.setEnabled(true);

        // drop book for transfer event handler
        catalogTree.setTransferHandler(new ChangeBookFolderTransferHandler());

        // folder tree add mouse listener in order to show popup menu.
        catalogTree.addMouseListener(new MouseAdapter() {

            @Override
            public void mouseClicked(MouseEvent e) {
                showBook("");
            }

            /**
             * FOR MAC OS X(Linux) RIGHT CLICK
             *
             */
            @Override
            public void mousePressed(MouseEvent mouseEvent) {
                if (mouseEvent.isPopupTrigger()) {
                    showTreePopupMenu(mouseEvent);
                }
            }

            /**
             * FOR WINDOWS RIGHT CLICK
             */
            @Override
            public void mouseReleased(MouseEvent mouseEvent) {
                if (mouseEvent.isPopupTrigger()) {
                    showTreePopupMenu(mouseEvent);
                }
            }
        });
    }

    private void initPopupMenu() {
        // create popup menu(a.k.a. context menu)
        // add item
        JMenuItem addmi = new JMenuItem(Configuration.getUIString("MainFrame.Add"),
                new ImageIcon(getClass().getResource("images/menu/add.png")));
        addmi.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                treeAddClick();
            }
        });
        // delete item
        JMenuItem delmi = new JMenuItem(Configuration.getUIString("MainFrame.Delete"),
                new ImageIcon(getClass().getResource("images/menu/delete.png")));
        delmi.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                treeDelClick();
            }
        });
        // configure item
        JMenuItem confmi = new JMenuItem(Configuration.getUIString("MainFrame.Configure"),
                new ImageIcon(getClass().getResource("images/menu/config.png")));
        confmi.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent actionEvent) {
                treeConfClick();
            }
        });
        catalogTreePopupMenu.add(addmi);
        catalogTreePopupMenu.add(delmi);
        catalogTreePopupMenu.add(confmi);
    }

    // ===============================
    // Event Process Section
    // ===============================
    private SettingDialog settingDialog;
    private void showSettingDialog() {
        // parent is MainFrame, modal is True.
        if(settingDialog == null) {
            settingDialog = new SettingDialog(this, true);
        }
        // show
        settingDialog.setVisible(true);
    }

    private void searchBook(String searchKey) {
        
        int selRow = bookTable.getSelectedRow();
        selRow = selRow + 1;

        for(int i = selRow; i < bookTable.getRowCount(); i++) {
            String bookName = (String) bookTable.getValueAt(i, 0);
            System.out.println("book name:" + bookName);
            System.out.println("search key:" + searchKey);
            if(bookName.contains(searchKey)) {
                bookTable.getSelectionModel().setSelectionInterval(i, i);
                return;
            }
        }

        JOptionPane.showMessageDialog(this, "Can not find more!");
        
    }

    private void renameBook() {
        int selRow = bookTable.getSelectedRow();
        if (selRow >= 0) {
            StringBuilder sb = new StringBuilder(currentSelectedCatalogTreePath);
            sb.append(Configuration.FILE_SEP);

            String bookName = (String) bookTable.getValueAt(selRow, 0);
            sb.append(bookName);

            String newName = JOptionPane.showInputDialog(this, "Please input new name for " + bookName, bookName);
            if(newName !=null && newName.length() > 0 && !newName.equalsIgnoreCase(bookName) ) {
                File fromFile = new File(sb.toString());
                File toFile = new File(fromFile.getParentFile().getAbsoluteFile(), newName);
                fromFile.renameTo(toFile);
                showBook("");
            }
        } else {
            JOptionPane.showMessageDialog(this, "Please select book to be renamed!");
        }
    }

    private void deleteBook() {
        int selRow = bookTable.getSelectedRow();
        if (selRow >= 0) {
            StringBuilder sb = new StringBuilder(currentSelectedCatalogTreePath);
            sb.append(Configuration.FILE_SEP);

            String bookName = (String) bookTable.getValueAt(selRow, 0);
            sb.append(bookName);

            int ret = JOptionPane.showConfirmDialog(this, "Are you sure to delete " + bookName + "?");
            if(ret == JOptionPane.OK_OPTION) {
                File bookFile = new File(sb.toString());
                bookFile.delete();
                showBook("");
            }
        } else {
            JOptionPane.showMessageDialog(this, "Please select book to be deleted!");
        }

    }

    /**
     * 
     */
    private void openBook() {
        if (Desktop.isDesktopSupported()) {

            Desktop d = Desktop.getDesktop();

            // book folder path
            StringBuilder sb = new StringBuilder(currentSelectedCatalogTreePath);
            sb.append(Configuration.FILE_SEP);

            // book name
            int selRow = bookTable.getSelectedRow();

            if (selRow >= 0) {

                String bookName = (String) bookTable.getValueAt(selRow, 0);
                sb.append(bookName);

                // Open book with proper tool.
                try {
                    d.open(new File(sb.toString()));
                } catch (IOException ex) {
                    JOptionPane.showMessageDialog(null, Configuration.getUIString("MainFrame.OpenFileFailedMsg") + sb.toString());
                }
            } else {
                JOptionPane.showMessageDialog(this, "Please select book first!");
            }
        }
    }

    private void showTreePopupMenu(MouseEvent mouseEvent) {
        Point mousePoint = mouseEvent.getPoint();
        TreePath tp = catalogTree.getClosestPathForLocation((int) mousePoint.getX(), (int) mousePoint.getY());
        catalogTree.addSelectionPath(tp);
        catalogTreePopupMenu.show(catalogTree, mouseEvent.getX(), mouseEvent.getY());
    }

    private String getCatalogTreeSelectedPath() {
        TreePath path = catalogTree.getSelectionPath();

        if (path == null) {
            return null;
        }

        Object[] items = path.getPath();
        StringBuilder sb = new StringBuilder();
        sb.append(Configuration.getBaseFolderPath());
        for (Object item : items) {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) item;
            CatalogUserObject userObj = (CatalogUserObject) node.getUserObject();
            String name = userObj.getName();

            sb.append(Configuration.FILE_SEP).append(name);
        }

        return sb.toString();
    }

    /**
     *
     * @param sbn selected book name.
     */
    private void showBook(String sbn) {

        int sbnIndex = -1;

        TreePath path = catalogTree.getSelectionPath();

        if (path == null) {
            return;
        }


        currentSelectedCatalogTreePath = getCatalogTreeSelectedPath();
        String relativePath = currentSelectedCatalogTreePath.substring(Configuration.getBaseFolderPath().length());
        // for open book use!


        File[] files = EBookMgrUtil.listAllFiles(currentSelectedCatalogTreePath, false);


        Vector header = new Vector();
        header.add(Configuration.getUIString("MainFrame.ShowBook.Name"));
        header.add(Configuration.getUIString("MainFrame.ShowBook.Size"));
        header.add(Configuration.getUIString("MainFrame.ShowBook.Star"));

        Vector data = new Vector();
        int index = -1;
        if (files != null && files.length > 0) {
            
            for (File f : files) {
                index ++;
                if(sbn.equalsIgnoreCase(f.getName())) {
                    sbnIndex = index;
                }


                Vector line = new Vector();
                line.add(f.getName());
                line.add(EBookMgrUtil.byteToKM(f.length()));
                int star = DatabaseUtil.getStar(conn, relativePath, f.getName());
                line.add(star);

                data.add(line);
            }

        } else {
            //nothing to add
        }

        // set table data and header
        DefaultTableModel tm = (DefaultTableModel) bookTable.getModel();
        tm.setDataVector(data, header);

        // make sortable
        RowSorter<TableModel> sorter = new TableRowSorter<TableModel>(tm);
        bookTable.setRowSorter(sorter);

        // set drag enable
        bookTable.setDragEnabled(true);

        // customer star cell renderer and editor
        if (data.size() > 0) {
            bookTable.getColumnModel().getColumn(2).setCellRenderer(new StarRenderer());
            bookTable.getColumnModel().getColumn(2).setCellEditor(new StarCellEditor());

            // add listener for star change
            bookTable.getModel().addTableModelListener(new TableModelListener() {

                @Override
                public void tableChanged(TableModelEvent e) {
                    int row = e.getFirstRow();
                    int col = e.getColumn();
                    if (row < 0 || col < 0) {
                        return;
                    } else {
                        changeBookStar(row, col);
                    }
                }
            });
        }

        // set default selection
        bookTable.getSelectionModel().setSelectionInterval(sbnIndex, sbnIndex);
        
        bookTable.repaint();
    }

    private void exitItemClick() {
        int ret = JOptionPane.showConfirmDialog(this, "Are you sure to exit?");
        if (ret == JOptionPane.OK_OPTION) {
            System.exit(0);
        }
    }

    private ImportDialog importDialog;
    private void importClick() {
        if(importDialog == null) {
            importDialog = new ImportDialog(this, true);
        } else {
            importDialog.reset();
        }
        importDialog.setVisible(true);
    }

    private AddFolderDialog addFolderDialog ;
    private void treeAddClick() {
        TreePath selPath = catalogTree.getSelectionPath();

        if (selPath == null) {
            // no select no show
            return;
        } else {

            // select show.
            Object[] pathItems = selPath.getPath();

            // show dialog
            if(addFolderDialog == null) {
                addFolderDialog = new AddFolderDialog(this, true);
            } else {
                addFolderDialog.setFolderName("");
                addFolderDialog.setKeyword("");
            }
            addFolderDialog.setVisible(true);

            if (addFolderDialog.isOK()) {

                String folderName = addFolderDialog.getFolderName();
                String keyword = addFolderDialog.getKeyword();
                int index = pathItems.length - 1;
                DefaultMutableTreeNode curNode = (DefaultMutableTreeNode) pathItems[index];

                DefaultMutableTreeNode addNode = new DefaultMutableTreeNode();
                CatalogUserObject userObj = new CatalogUserObject(folderName, keyword);
                addNode.setUserObject(userObj);

                DefaultTreeModel tm = (DefaultTreeModel) catalogTree.getModel();
                tm.insertNodeInto(addNode, curNode, curNode.getChildCount());

                TreeUtil.saveTree(catalogTree.getModel());

            }
        }
    }

    private void treeDelClick() {

        int ret = JOptionPane.showConfirmDialog(this, Configuration.getUIString("MainFrame.DeleteMsg"));

        if (ret == JOptionPane.CANCEL_OPTION || ret == JOptionPane.NO_OPTION) {
            return;
        }

        TreePath selPath = catalogTree.getSelectionPath();

        if (selPath == null) {
            // no select no show
            return;
        } else {
            Object[] pathItems = selPath.getPath();
            int index = pathItems.length - 1;
            DefaultMutableTreeNode curNode = (DefaultMutableTreeNode) pathItems[index];
            int childCnt = curNode.getChildCount();
            if (childCnt == 0) {
                // delete leaf
                DefaultTreeModel tm = (DefaultTreeModel) catalogTree.getModel();
                tm.removeNodeFromParent(curNode);

                TreeUtil.saveTree(catalogTree.getModel());

            } else {
                JOptionPane.showMessageDialog(this, Configuration.getUIString("MainFrame.DeleteLeafOnlyMsg"));
            }
        }
    }

    private void treeConfClick() {
        TreePath selPath = catalogTree.getSelectionPath();

        if (selPath == null) {
            // no select no show
            return;
        } else {
            Object[] pathItems = selPath.getPath();
            int index = pathItems.length - 1;
            DefaultMutableTreeNode curNode = (DefaultMutableTreeNode) pathItems[index];

            int childCnt = curNode.getChildCount();
            if (childCnt == 0) {
                CatalogUserObject userObj = (CatalogUserObject) curNode.getUserObject();

                if(addFolderDialog == null) {
                    addFolderDialog = new AddFolderDialog(this, true);
                }
                addFolderDialog.setFolderName(userObj.getName());
                addFolderDialog.setKeyword(userObj.getKeyword());
                addFolderDialog.setVisible(true);

                if (addFolderDialog.isOK()) {
                    userObj.setName(addFolderDialog.getFolderName());
                    userObj.setKeyword(addFolderDialog.getKeyword());
                    TreeUtil.saveTree(catalogTree.getModel());
                }

            } else {
                JOptionPane.showMessageDialog(this, Configuration.getUIString("MainFrame.ConfigureLeafOnlyMsg"));
            }
        }
    }

    private void changeBookStar(int row, int col) {

        String path = this.getCatalogTreeSelectedPath().substring(Configuration.getBaseFolderPath().length());
        String name = (String) bookTable.getValueAt(row, 0);
        Integer star = (Integer) bookTable.getValueAt(row, col);

        System.out.println("path:" + path);
        System.out.println("name:" + name);
        System.out.println("star:" + star);

        DatabaseUtil.updateStar(conn, path, name, star);

    }

    private AboutDialog aboutDialog;
    private void showAboutDialog() {
        if(aboutDialog == null) {
            aboutDialog = new AboutDialog(this, true);
        }
        aboutDialog.setVisible(true);
    }

    private void showHelpContent() {
        System.out.println("user click help menu item");
    }

    public class CopyFileDropListener implements DropTargetListener {

        @Override
        public void dragEnter(DropTargetDragEvent dtde) {
            System.out.println("drag enter");
        }

        @Override
        public void dragOver(DropTargetDragEvent dtde) {
            System.out.println("drag over");
        }

        @Override
        public void dropActionChanged(DropTargetDragEvent dtde) {
            System.out.println("drop action changed");
        }

        @Override
        public void dragExit(DropTargetEvent dte) {
            System.out.println("drop exit");
        }

        @Override
        public void drop(DropTargetDropEvent dtde) {
            try {
                Transferable ta = dtde.getTransferable();
                DataFlavor[] dfs = ta.getTransferDataFlavors();
                for (DataFlavor df : dfs) {
                    if (df.isFlavorJavaFileListType()) {
                        dtde.acceptDrop(DnDConstants.ACTION_COPY);
                        List dataList = (List) ta.getTransferData(df);
                        for (Object data : dataList) {
                            System.out.println("data type:" + data.getClass());
                            System.out.println("data value:" + data.toString());
                            if(data instanceof File) {
                                File dropFile = (File)data;
                                String filePath = dropFile.getAbsolutePath();
                                if(ImportUtil.isEBook(filePath)) {
                                    // TODO: add exception process here.
                                    ImportUtil.copyFile(filePath, currentSelectedCatalogTreePath);
                                    showBook(dropFile.getName());
                                }
                            }
                        }
                    }
                }
            } catch (Exception ex) {
                ex.printStackTrace();
                dtde.rejectDrop();
            }
        }
    }

    class ChangeBookFolderTransferHandler extends TransferHandler {

        @Override
        public boolean canImport(TransferSupport support) {

            return true;
        }

        @Override
        public boolean importData(TransferSupport support) {
            StringBuilder sb = new StringBuilder(Configuration.getBaseFolderPath());

            JTree.DropLocation droploc = (JTree.DropLocation) support.getDropLocation();
            TreePath tp = droploc.getPath();
            Object[] items = tp.getPath();
            for (Object item : items) {
                DefaultMutableTreeNode node = (DefaultMutableTreeNode) item;
                CatalogUserObject userObj = (CatalogUserObject) node.getUserObject();
                sb.append(Configuration.FILE_SEP).append(userObj.getName());
            }

            System.out.println("to folder:" + sb.toString());

            String transferData = null;
            try {
                transferData = (String) support.getTransferable().getTransferData(DataFlavor.stringFlavor);
            } catch (UnsupportedFlavorException ex) {
                Logger.getLogger(ChangeBookFolderTransferHandler.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(ChangeBookFolderTransferHandler.class.getName()).log(Level.SEVERE, null, ex);
            }



            String[] its = transferData.split("\t");
            String fromFileName = its[0];

            String fromPath = currentSelectedCatalogTreePath + Configuration.FILE_SEP + fromFileName;
            System.out.println("from path;" + fromPath);

            // todo: copy fromPaht to toFolder
            // @TODO: to be test
            File fromFile = new File(fromPath);
            File toFile = new File(sb.toString(), fromFile.getName());

            if(!toFile.getParentFile().exists()) {
                toFile.getParentFile().mkdirs();
            }

            boolean ret = fromFile.renameTo(toFile);



            System.out.println("from:" + fromFile.getAbsolutePath());
            System.out.println("to:" + toFile.getAbsolutePath());
            System.out.println("move file:" + ret);

            catalogTree.setSelectionPath(tp);
            catalogTree.repaint();
            showBook(toFile.getName());

            return true;
        }
    }
}

/**
 * disable all cell editable.
 * @author mazhao
 */
class BookTableModel extends DefaultTableModel {

    @Override
    public boolean isCellEditable(int row, int column) {
        // only star can change
        if (column == 2) {
            return true;
        } else {
            return false;
        }
    }
}

class StarRenderer extends DefaultTableCellRenderer {

    @Override
    protected void setValue(Object value) {
        int star = ((Integer) value).intValue();

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < star; i++) {
            sb.append(Configuration.getStar());
        }

        super.setValue(sb.toString());
    }
}

class StarCellEditor extends AbstractCellEditor implements TableCellEditor {

    private JComboBox combox = new JComboBox();

    public StarCellEditor() {
        for (int i = 1; i <= 5; i++) {
            combox.addItem(getStrValue(i));
        }
    }

    private String getStrValue(int v) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < v; i++) {
            sb.append(Configuration.getStar());
        }
        return sb.toString();
    }

    private int getIntValue(String str) {
        return str.length();
    }

    @Override
    public Object getCellEditorValue() {
        int value = getIntValue((String) combox.getSelectedItem());
        return new Integer(value);
    }

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        int iv = ((Integer) value).intValue();
        combox.setSelectedIndex(iv - 1);
        return combox;
    }
}

